/**
 * 弹窗插件
 * @author 贾迎博
 * @description
 * 需要所有弹窗设置类名 pop弹窗关闭按钮设置类名 close(需要关闭时拉起上一个弹窗再添加popPrev类名)
 * 弹窗popup() 隐藏弹窗或遮罩hideMask() 修改遮罩样式方法maskLayerCss()
 * @example popup('#id')
 * @todo 整合全局config
 *        -- 隐藏显示动画
 */

(function (global, factory) {
    global = global || self;
    $.extend(global, factory())
}(this, function () {
    'use strict';

    /** 公共参数 */
    var Global = {
        /** 所有弹窗的公共类名 */
        popName: '.pop',
        /** 要弹出的元素 jq对象 */
        ele: undefined,
        /** 遮罩层ID */
        maskLayerID: '_MaskLayer',
        /** style标签ID */
        styleID: 'popupCss',
        /** 背景锁定样式名 */
        scrollLockClass: '_popupScrollLock',
        /** 弹出上一个的类名 */
        popPrev: 'popPrev',
        /** 记录弹窗的顺序 */
        popLog: [],
        /** 滚动位置的坐标 防止设置||取消fixed定位后 body自动滚动到顶部的问题 */
        windowScrollTop: null,
        windowScrollLeft: null
    };

    var config = {
        /** 是否弹出上一个弹窗 */
        popPrev: false,
        /** 是否开启背景锁定 默认开启 */
        scrollLock: true,
        /** 动画效果 */
        jqAnimationOpt: {},
    };

    /** 初始化 */
    var init = function () {
        if ($.fn.jquery.indexOf('1.') !== -1) console.warn('！！！！！！！！！！！！！！！！！推荐使用3.x版本jQuery！！！！！！！！！！！！！！！！！');

        maskLayer.addMaskLayer();
        popup.addStyleBlock();

        // 隐藏弹窗的两种方式，点击关闭按钮或者按下esc
        $('.pop').on('click touchstart', '.close',function (e) {
            e.preventDefault();
            e.stopPropagation();

            hideMask();
        });
        window.onkeydown = function (e) { if (e.code == 'Escape') { hideMask() } }
    };

    /** 重置坐标参数 */
    var reset = function () {
        Global.windowScrollTop && $(window).scrollTop(Global.windowScrollTop);
        Global.windowScrollLeft && $(window).scrollLeft(Global.windowScrollLeft);

        Global.windowScrollTop = null;
        Global.windowScrollLeft = null;
    };

    /** 遮罩层模块 */
    var maskLayer = {
        /**
         * 添加遮罩层依赖元素
         */
        addMaskLayerDiv: function () {
            var MaskLayer = $('<div id="' + Global.maskLayerID + '" />');

            $('#' + Global.maskLayerID)[0] || $('body').append(MaskLayer);
        },
        /**
         * 定义遮罩层样式
         */
        maskLayerCss: function (options) {
            var MaskLayerCss = {
                display: 'none',
                position: 'fixed',
                zIndex: '100',
                top: '0px',
                left: '0px',
                height: '100%',
                width: '100%',
                backgroundColor: 'rgba(0, 0, 0, 0.6)'
            };
            options && $.extend(MaskLayerCss, options);
            $('#' + Global.maskLayerID).removeAttr('style').css(MaskLayerCss);
        },
        /**
         * 添加遮罩层
         */
        addMaskLayer: function () {
            this.addMaskLayerDiv();
            this.maskLayerCss();
        },
        /**
         * 移除遮罩层
         */
        removeMaskLayer: function () {
            if ('#' + $(Global.maskLayerID)[0]) $('#' + Global.maskLayerID).remove();
        },
        /** 隐藏遮罩 */
        hideMaskLayer: function () {
            $('#' + Global.maskLayerID).fadeOut();
        },
        /** 显示遮罩 */
        showMaskLayer: function () {
            $('#' + Global.maskLayerID).finish();
            $('#' + Global.maskLayerID).css('display') !== "block" && $('#' + Global.maskLayerID).show();
        }
    };

    /** 弹窗模块 */
    var popup = {
        /**
         * 添加style标签供类名样式修改使用
         */
        // FIXME overscroll-behavior: contain 这个属性iOS中不生效
        addStyleBlock: function () {
            $('body').append('<style id="' + Global.styleID + '">#' + Global.maskLayerID + ', .pop {overscroll-behavior: contain; /*防止滚动穿透详见mdn*/ -webkit-transform: translate3d(0,0,0); /*防止iOS按钮点击异常BUG*/ will-change: transform, opacity;}</style>');
        },
        /**
         * 添加背景锁定（防滚动穿透）css
         */
        addScrollLockCss: function () {
            Global.windowScrollTop = $(window).scrollTop(); // 若是获取到的高度为0 看下是不是没给html,body设置height:100%
            Global.windowScrollLeft = $(window).scrollLeft();

            $('#popupCss').append("body._popupScrollLock {" +
                "width: " + $('body').width() + "px;" +
                "overflow: hidden;" +
                "position: fixed;" +
                "top: " + (-Global.windowScrollTop) + "px;" +
                "left: " + Global.windowScrollLeft + "px;}");

            $('body').addClass(Global.scrollLockClass);
        },
        /**
         * 计算元素定位 重置滚动坐标等
         */
        elePosition: function () {
            var top = ($(window).height() - Global.ele.outerHeight()) / 2 + (config.scrollLock || $(window).scrollTop()),
                left = ($(window).width() - Global.ele.outerWidth()) / 2 + (config.scrollLock || $(window).scrollLeft());
            /**
             * 问题描述：输入内容键盘弹起页面整体上移，但键盘收起页面内容不下滑；
             * 解决：fixed定位的元素在iOS中会出现此问题，特别是使用第三方输入法时
             */
            var xyz = {
                "position": config.scrollLock ? "fixed" : "absolute",
                "top": (top < 0 ? 0 : top),
                "left": (left < 0 ? 0 : left),
                "z-index": "999"
            };

            Global.ele.css(xyz);

            return Global.ele;
        },
        /**
         * 包装
         * @description
         * 在安卓中键盘弹出(iOS待测试)可能会将输入框遮挡,检测当前获取焦点的输入框将其移入可视区域
         * 延时是因为安卓键盘弹出有延迟
         */
        pack: function () {
            popup.elePosition();

            setTimeout(function () {
                // Element.scrollIntoViewIfNeeded()方法用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。如果该元素已经在浏览器窗口的可见区域内，则不会发生滚动
                Global.ele.find('input:focus, textarea:focus')[0] && Global.ele.find('input:focus, textarea:focus')[0].scrollIntoViewIfNeeded()
            }, 300)
        },
        /**
         * 弹窗方法
         * @param { String } ele 元素选择器
         * @param { Boolean } popPrev 是否弹出上一个弹窗
         * @param { Boolean } scrollLock 是否开启背景锁定 防止滚动穿透 默认开启
         * @param { Object } popAnimation {ani: jq支持的动画效果,speed: jq支持的速度参数} 见jq文档；
         * @example popup('#id', false, {ani: 'slideDown', speed: 'slow'})
         */
        pop: function (ele, popPrev, scrollLock, popAnimation) {
            if (ele && $(ele).length) {
                Global.ele = $(ele);
            } else {
                throw new Error('~~~~未传入元素选择器或元素选择器筛选结果为空: ' + ele + ' ~~~~');
            };

            Global.popLog.push($(ele));

            scrollLock !== undefined ? (config.scrollLock = !!scrollLock) : (config.scrollLock = true);
            popAnimation && (config.jqAnimationOpt = popAnimation);

            maskLayer.showMaskLayer();

            if ($('.pop:visible')[0] !== Global.ele[0]) { $(Global.popName).hide(); };
            popup.elePosition()[popAnimation && popAnimation.ani || 'fadeIn'](popAnimation && popAnimation.speed || 'fast');

            if (config.scrollLock) {
                $('body').hasClass(Global.scrollLockClass) || popup.addScrollLockCss();
            } else {
                $('body').removeClass(Global.scrollLockClass);
                reset();
            }

            config.popPrev = popPrev;

            $(window).on('resize scroll', popup.pack);
        }
    };

    /**
     * 隐藏弹窗跟遮罩
     * @param {*} ele 元素选择器
     * @param {*} hideAnimation 动画
     */
    function hideMask(ele, hideAnimation) {

        maskLayer.hideMaskLayer();

        ele = ele || Global.popName;

        // 从弹窗记录队列中删掉将要关闭的这个弹窗
        Global.popLog = $.grep(Global.popLog, function (n) {
            return n[0] == $('.pop:visible')[0];
        }, true);

        var last = Global.popLog.pop();
        if (($('.pop:visible .close').hasClass(Global.popPrev) || config.popPrev) && last) {
            popup.pop(last);
            return;
        };

        $(ele).finish();
        $(ele)[hideAnimation && hideAnimation.ani || 'fadeOut'](hideAnimation && hideAnimation.speed || 'fast');

        $('body').removeClass(Global.scrollLockClass);

        $(window).scrollTop(Global.windowScrollTop);
        $(window).scrollLeft(Global.windowScrollLeft);

        $(window).off('resize scroll', popup.pack);
    };

    init();

    return {
        popup: popup.pop,
        hideMask: hideMask,
        maskLayerCss: maskLayer.maskLayerCss,
        showMaskLayer: maskLayer.showMaskLayer,
        hideMaskLayer: maskLayer.hideMaskLayer,
        /**
         * 获取所有的内部模块 浅拷贝方便查看
         * @example var dialog = getAllPopModule()
         */
        getAllPopModule: function () {
            return {
                'person': Global,
                'rest': reset,
                'maskLayer': maskLayer,
                'popup': popup,
                'hideMask': hideMask
            }
        }
    };
}))
